package verify

import (
	"context"
	"crypto/tls"
	"fmt"
	"io"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"

	googledns "dns-tools/pkg/dns"
	"dns-tools/pkg/dnssec"

	mdns "github.com/miekg/dns"
)

// VerificationMethod 验证方法
type VerificationMethod string

const (
	MethodDNSTXT   VerificationMethod = "DNS_TXT"
	MethodDNSCNAME VerificationMethod = "DNS_CNAME"
	MethodHTTP     VerificationMethod = "HTTP"
	MethodHTTPS    VerificationMethod = "HTTPS"
	MethodFile     VerificationMethod = "FILE"
)

// VerificationTask 验证任务
type VerificationTask struct {
	Domain        string             `json:"domain,omitempty"`
	URL           string             `json:"url,omitempty"`
	Method        VerificationMethod `json:"method"`
	ExpectedValue string             `json:"expected_value"`
	Timeout       time.Duration      `json:"-"`
}

// VerificationResult 验证结果
type VerificationResult struct {
	Domain       string             `json:"domain,omitempty"`
	URL          string             `json:"url,omitempty"`
	Method       VerificationMethod `json:"method"`
	Success      bool               `json:"success"`
	Message      string             `json:"message"`
	ActualValue  string             `json:"actual_value,omitempty"`
	ResponseTime time.Duration      `json:"response_time"`
	VerifiedAt   time.Time          `json:"verified_at"`
	Error        string             `json:"error,omitempty"`

	// 以下字段用于 FILE 方法的调试信息（不直接对外返回，由 handler 组装）
	LinkHTTPS    string `json:"-"`
	LinkHTTP     string `json:"-"`
	ContentHTTPS string `json:"-"`
	ContentHTTP  string `json:"-"`

	// DNSSEC 检测信息（仅 DNS 方法）
	DNSSEC *googledns.DNSSECInfo `json:"dnssec,omitempty"`
}

// DNSResolver DNS 解析器接口
type DNSResolver interface {
	LookupTXT(ctx context.Context, domain string) ([]string, error)
	LookupCNAME(ctx context.Context, domain string) (string, error)
}

// StandardDNSResolver 标准 DNS 解析器
type StandardDNSResolver struct {
	resolver *net.Resolver
}

func NewStandardDNSResolver() *StandardDNSResolver {
	return &StandardDNSResolver{
		resolver: &net.Resolver{
			PreferGo: true,
			Dial: func(ctx context.Context, network, address string) (net.Conn, error) {
				d := net.Dialer{
					Timeout: 3 * time.Second,
				}
				return d.DialContext(ctx, network, address)
			},
		},
	}
}

func (r *StandardDNSResolver) LookupTXT(ctx context.Context, domain string) ([]string, error) {
	return r.resolver.LookupTXT(ctx, domain)
}

func (r *StandardDNSResolver) LookupCNAME(ctx context.Context, domain string) (string, error) {
	return r.resolver.LookupCNAME(ctx, domain)
}

// BatchVerifier 批量验证器
type BatchVerifier struct {
	maxConcurrency int
	timeout        time.Duration
	httpClient     *http.Client
	dnsResolver    DNSResolver
	dnssecDetector *dnssec.Detector
}

// Option 配置选项
type Option func(*BatchVerifier)

// WithMaxConcurrency 设置最大并发数
func WithMaxConcurrency(n int) Option {
	return func(v *BatchVerifier) {
		if n <= 0 {
			n = 10
		}
		if n > 50 {
			n = 50
		}
		v.maxConcurrency = n
	}
}

// WithTimeout 设置超时时间
func WithTimeout(timeout time.Duration) Option {
	return func(v *BatchVerifier) {
		v.timeout = timeout
	}
}

// WithHTTPClient 设置 HTTP 客户端
func WithHTTPClient(client *http.Client) Option {
	return func(v *BatchVerifier) {
		v.httpClient = client
	}
}

// WithDNSResolver 设置 DNS 解析器（用于 TXT/CNAME）
func WithDNSResolver(resolver DNSResolver) Option {
	return func(v *BatchVerifier) {
		if resolver != nil {
			v.dnsResolver = resolver
		}
	}
}

// NewBatchVerifier 创建批量验证器
func NewBatchVerifier(opts ...Option) *BatchVerifier {
	v := &BatchVerifier{
		maxConcurrency: 10,
		timeout:        10 * time.Second,
		dnsResolver:    NewStandardDNSResolver(),
		dnssecDetector: dnssec.NewDetector(), // 初始化 DNSSEC 检测器
	}

	for _, opt := range opts {
		opt(v)
	}

	if v.httpClient == nil {
		v.httpClient = &http.Client{
			Timeout: v.timeout,
			CheckRedirect: func(req *http.Request, via []*http.Request) error {
				if len(via) >= 10 {
					return fmt.Errorf("too many redirects")
				}
				return nil
			},
		}
	}

	return v
}

// ProcessBatch 处理批量验证
func (v *BatchVerifier) ProcessBatch(ctx context.Context, tasks []VerificationTask) []VerificationResult {
	if len(tasks) == 0 {
		return []VerificationResult{}
	}

	results := make([]VerificationResult, len(tasks))
	var wg sync.WaitGroup
	semaphore := make(chan struct{}, v.maxConcurrency)

	for i, task := range tasks {
		wg.Add(1)
		go func(index int, t VerificationTask) {
			defer wg.Done()

			semaphore <- struct{}{}
			defer func() { <-semaphore }()

			// 为每个任务创建超时上下文
			taskCtx, cancel := context.WithTimeout(ctx, v.timeout)
			defer cancel()

			var result VerificationResult
			switch t.Method {
			case MethodDNSTXT:
				result = v.VerifyDNSTXT(taskCtx, t.Domain, t.ExpectedValue)
			case MethodDNSCNAME:
				result = v.VerifyDNSCNAME(taskCtx, t.Domain, t.ExpectedValue)
			case MethodHTTP:
				result = v.VerifyHTTP(taskCtx, t.URL, t.ExpectedValue)
			case MethodHTTPS:
				result = v.VerifyHTTPS(taskCtx, t.URL, t.ExpectedValue)
			case MethodFile:
				result = v.VerifyFile(taskCtx, t.URL, t.ExpectedValue)
			default:
				result = VerificationResult{
					Domain:     t.Domain,
					URL:        t.URL,
					Method:     t.Method,
					Success:    false,
					Message:    "Unsupported verification method",
					VerifiedAt: time.Now(),
				}
			}

			results[index] = result
		}(i, task)
	}

	wg.Wait()
	return results
}

// VerifyDNSTXT 验证 DNS TXT 记录
func (v *BatchVerifier) VerifyDNSTXT(ctx context.Context, domain, expectedValue string) VerificationResult {
	start := time.Now()
	result := VerificationResult{
		Domain:     domain,
		Method:     MethodDNSTXT,
		VerifiedAt: time.Now(),
	}

	records, err := v.dnsResolver.LookupTXT(ctx, domain)
	result.ResponseTime = time.Since(start)

	if err != nil {
		result.Success = false
		result.Message = "Failed to lookup DNS TXT record"
		result.Error = err.Error()
		// 即使失败也尝试 DNSSEC 检测
		if v.dnssecDetector != nil {
			dnssecInfo := v.dnssecDetector.DetectState(ctx, domain, mdns.TypeTXT)
			result.DNSSEC = dnssecInfo
		}
		return result
	}

	if len(records) == 0 {
		result.Success = false
		result.Message = "No DNS TXT record found"
		// DNSSEC 检测
		if v.dnssecDetector != nil {
			dnssecInfo := v.dnssecDetector.DetectState(ctx, domain, mdns.TypeTXT)
			result.DNSSEC = dnssecInfo
		}
		return result
	}

	// 规范化 TXT：仅去除两侧引号（传入 expected 不带引号，无需处理）
	normalizeTXT := func(s string) string {
		s = strings.TrimSpace(s)
		if len(s) >= 2 && strings.HasPrefix(s, "\"") && strings.HasSuffix(s, "\"") {
			return s[1 : len(s)-1]
		}
		return s
	}

	// 检查是否有匹配的记录（对查询值去两侧引号后比较，忽略大小写）
	matchFound := false
	for _, record := range records {
		norm := normalizeTXT(record)
		if strings.EqualFold(norm, expectedValue) {
			result.Success = true
			result.Message = "DNS TXT record verified successfully"
			result.ActualValue = norm
			matchFound = true
			break
		}
	}

	if !matchFound {
		result.Success = false
		result.Message = "DNS TXT record value mismatch"
		// 失败时返回所有查询值（去两侧引号后）
		if len(records) > 0 {
			vals := make([]string, 0, len(records))
			for _, r := range records {
				vals = append(vals, normalizeTXT(r))
			}
			result.ActualValue = strings.Join(vals, ", ")
		}
	}

	// DNSSEC 检测（非阻塞）
	if v.dnssecDetector != nil {
		dnssecInfo := v.dnssecDetector.DetectState(ctx, domain, mdns.TypeTXT)
		result.DNSSEC = dnssecInfo

		// 如果有风险，在 Message 中添加提示
		if dnssecInfo != nil && dnssecInfo.RiskLevel != googledns.DNSSECRiskNone {
			dnssecMsg := dnssec.FormatDNSSECMessage(dnssecInfo)
			if dnssecMsg != "" {
				result.Message += dnssecMsg
			}
		}
	}

	return result
}

// VerifyDNSCNAME 验证 DNS CNAME 记录
func (v *BatchVerifier) VerifyDNSCNAME(ctx context.Context, domain, expectedValue string) VerificationResult {
	start := time.Now()
	result := VerificationResult{
		Domain:     domain,
		Method:     MethodDNSCNAME,
		VerifiedAt: time.Now(),
	}

	cname, err := v.dnsResolver.LookupCNAME(ctx, domain)
	result.ResponseTime = time.Since(start)

	if err != nil {
		result.Success = false
		result.Message = "Failed to lookup DNS CNAME record"
		result.Error = err.Error()
		// 即使失败也尝试 DNSSEC 检测
		if v.dnssecDetector != nil {
			dnssecInfo := v.dnssecDetector.DetectState(ctx, domain, mdns.TypeCNAME)
			result.DNSSEC = dnssecInfo
		}
		return result
	}

	if cname == "" {
		result.Success = false
		result.Message = "No DNS CNAME record found"
		// DNSSEC 检测
		if v.dnssecDetector != nil {
			dnssecInfo := v.dnssecDetector.DetectState(ctx, domain, mdns.TypeCNAME)
			result.DNSSEC = dnssecInfo
		}
		return result
	}

	// 标准化 CNAME（去除尾部的点）
	cname = strings.TrimSuffix(cname, ".")
	expectedValue = strings.TrimSuffix(expectedValue, ".")

	// 忽略大小写进行比较
	if strings.EqualFold(cname, expectedValue) {
		result.Success = true
		result.Message = "DNS CNAME record verified successfully"
		result.ActualValue = cname
	} else {
		result.Success = false
		result.Message = "DNS CNAME record value mismatch"
		result.ActualValue = cname
	}

	// DNSSEC 检测（非阻塞）
	if v.dnssecDetector != nil {
		dnssecInfo := v.dnssecDetector.DetectState(ctx, domain, mdns.TypeCNAME)
		result.DNSSEC = dnssecInfo

		// 如果有风险，在 Message 中添加提示
		if dnssecInfo != nil && dnssecInfo.RiskLevel != googledns.DNSSECRiskNone {
			dnssecMsg := dnssec.FormatDNSSECMessage(dnssecInfo)
			if dnssecMsg != "" {
				result.Message += dnssecMsg
			}
		}
	}

	return result
}

// VerifyHTTP 验证 HTTP 内容
func (v *BatchVerifier) VerifyHTTP(ctx context.Context, url, expectedValue string) VerificationResult {
	return v.verifyHTTPContent(ctx, url, expectedValue, MethodHTTP)
}

// VerifyHTTPS 验证 HTTPS 内容
func (v *BatchVerifier) VerifyHTTPS(ctx context.Context, url, expectedValue string) VerificationResult {
	// 确保 URL 使用 HTTPS
	if strings.HasPrefix(url, "http://") {
		url = "https://" + strings.TrimPrefix(url, "http://")
	} else if !strings.HasPrefix(url, "https://") {
		url = "https://" + url
	}

	return v.verifyHTTPContent(ctx, url, expectedValue, MethodHTTPS)
}

// VerifyFile 验证文件内容（支持 // 协议前缀）
func (v *BatchVerifier) VerifyFile(ctx context.Context, url, expectedValue string) VerificationResult {
	// 处理 // 形式的 URL（同时尝试 HTTP 和 HTTPS）
	if strings.HasPrefix(url, "//") {
		// 先尝试 HTTPS
		httpsURL := "https:" + url
		httpsResult := v.verifyHTTPContent(ctx, httpsURL, expectedValue, MethodFile)
		// 记录 HTTPS 调试信息
		httpsResult.LinkHTTPS = httpsURL
		if httpsResult.ActualValue != "" {
			httpsResult.ContentHTTPS = httpsResult.ActualValue
		}
		if httpsResult.Success {
			return httpsResult
		}

		// 如果 HTTPS 失败，尝试 HTTP
		httpURL := "http:" + url
		httpResult := v.verifyHTTPContent(ctx, httpURL, expectedValue, MethodFile)
		// 合并调试信息（保留 HTTPS 的响应）
		httpsResult.LinkHTTP = httpURL
		if httpResult.ActualValue != "" {
			httpsResult.ContentHTTP = httpResult.ActualValue
		}
		if httpResult.Success {
			return httpResult
		}

		// 两者都失败，返回 HTTPS 的结果（优先）
		httpsResult.Message = "File verification failed for both HTTPS and HTTP"
		return httpsResult
	}

	// 对于显式协议的 URL，补充 LinkHTTPS/LinkHTTP 以便失败时回包
	res := v.verifyHTTPContent(ctx, url, expectedValue, MethodFile)
	if strings.HasPrefix(url, "https://") {
		res.LinkHTTPS = url
		alt := "http://" + strings.TrimPrefix(url, "https://")
		res.LinkHTTP = alt
	} else if strings.HasPrefix(url, "http://") {
		res.LinkHTTP = url
		alt := "https://" + strings.TrimPrefix(url, "http://")
		res.LinkHTTPS = alt
	}
	return res
}

// verifyHTTPContent 通用 HTTP 内容验证
func (v *BatchVerifier) verifyHTTPContent(ctx context.Context, url, expectedValue string, method VerificationMethod) VerificationResult {
	start := time.Now()
	result := VerificationResult{
		URL:        url,
		Method:     method,
		VerifiedAt: time.Now(),
	}

	req, err := http.NewRequestWithContext(ctx, "GET", url, nil)
	if err != nil {
		result.Success = false
		result.Message = "Failed to create request"
		result.Error = err.Error()
		return result
	}

	// 按旧版语义：当为 HTTPS 或 FILE(HTTPS) 时忽略证书错误
	client := v.httpClient
	if strings.HasPrefix(url, "https://") && (method == MethodHTTPS || method == MethodFile) {
		client = &http.Client{
			Timeout:       v.timeout,
			CheckRedirect: v.httpClient.CheckRedirect,
			Transport:     &http.Transport{TLSClientConfig: &tls.Config{InsecureSkipVerify: true}},
		}
	}

	resp, err := client.Do(req)
	result.ResponseTime = time.Since(start)

	if err != nil {
		result.Success = false
		result.Message = "Failed to fetch content"
		result.Error = err.Error()
		return result
	}
	defer resp.Body.Close()

	if resp.StatusCode != http.StatusOK {
		result.Success = false
		result.Message = fmt.Sprintf("HTTP status code: %d", resp.StatusCode)
		return result
	}

	// 读取响应内容（限制大小）
	body, err := io.ReadAll(io.LimitReader(resp.Body, 1024*1024)) // 1MB limit
	if err != nil {
		result.Success = false
		result.Message = "Failed to read response body"
		result.Error = err.Error()
		return result
	}

	content := strings.TrimSpace(string(body))

	// 忽略大小写比较文件/HTTP内容
	if strings.EqualFold(content, expectedValue) {
		result.Success = true
		switch method {
		case MethodHTTP:
			result.Message = "HTTP content verified successfully"
		case MethodHTTPS:
			result.Message = "HTTPS content verified successfully"
		case MethodFile:
			result.Message = "File content verified successfully"
		}
		result.ActualValue = content
	} else {
		result.Success = false
		switch method {
		case MethodHTTP:
			result.Message = "HTTP content mismatch"
		case MethodHTTPS:
			result.Message = "HTTPS content mismatch"
		case MethodFile:
			result.Message = "File content mismatch"
		}
		// 限制实际值的长度（所有 link 查询统一 1000）
		limit := 1000
		if len(content) > limit {
			result.ActualValue = content[:limit] + "..."
		} else {
			result.ActualValue = content
		}
	}

	return result
}

// BatchVerificationRequest 批量验证请求
type BatchVerificationRequest struct {
	Tasks []VerificationTask `json:"tasks"`
}

// BatchVerificationResponse 批量验证响应
type BatchVerificationResponse struct {
	Results   []VerificationResult `json:"results"`
	Total     int                  `json:"total"`
	Success   int                  `json:"success"`
	Failed    int                  `json:"failed"`
	Duration  time.Duration        `json:"duration"`
	Timestamp time.Time            `json:"timestamp"`
}
